#include "MutaTendril.h"
#include "qwt/qwt_curve_fitter.h"
#include <QTime>

MutaTendril::MutaTendril(QString owner,QPointF p1,QPointF p2,int layer):
    MutaObject(owner.append(QString().number(MutaObject::getObjectCount())),Muta::AutoTendril,owner),
    QGraphicsPathItem(),
    layer(layer),
    time(0),
    boxColor(155,255,255,10),
    numTendrils(8),
    mode(MutaTendril::Melding),
    deviance(120)
{
    setPos(p1);
    setFlag( QGraphicsItem::ItemIsSelectable, true );
    setFlag( QGraphicsItem::ItemIsMovable, true );
    setFlag(QGraphicsItem::ItemSendsGeometryChanges);

    //controlPoints = QVector()
    for(int n=0;n<numTendrils;n++) {
        //QList* list = new QList<ControlPoint*>();
        controlPoints.append(new QList<ControlPoint*>());
    }

    addControlPoint(p1);
    //controlPoints.first()->setFlag( QGraphicsItem::ItemIsSelectable, false );
    //controlPoints.first()->setFlag( QGraphicsItem::ItemIsMovable, false );
    addControlPoint(p2+this->pos());

    boxBrush.setColor(boxColor);
    boxBrush.setStyle(Qt::SolidPattern);
    boxPen.setWidth(1);
    boxPen.setColor(boxColor);
}

void MutaTendril::buildPath()
{
    QPainterPath path;
    for(int n=0;n<numTendrils;n++) {
        QPolygonF polygon;
        for(int i=0;i<controlPoints.at(n)->size();i++) {
            polygon.append(controlPoints.at(n)->at(i)->pos());
        }
        QwtSplineCurveFitter curveFitter;
        polygon = curveFitter.fitCurve(polygon);
        path.addPolygon(polygon);
        if(n<numTendrils-1) {
            path.moveTo(controlPoints.at(n)->at(0)->pos());
        }
    }

    setPath(path);
}

int MutaTendril::type() const
{
    return mutaType;
}

void MutaTendril::addControlPoint(QPointF point) {
    controlPoints.at(0)->append(new ControlPoint(Muta::quantizePoint(point,Muta::BEAT_PIXELS,15)-this->pos()+QPointF(0,7.5),controlPoints.at(0)->size(),-5,-5,10,10,this));
    QObject::connect(controlPoints.at(0)->at(controlPoints.at(0)->size() -1),SIGNAL(mouseMoved(QPointF,int)),this,SLOT(cPointMoved(QPointF,int)));

    QTime time = QTime::currentTime();
    qsrand((uint)time.msec());

    for(int n=1;n<numTendrils;n++) {
        if(mode==MutaTendril::Melding) {
            if((controlPoints.at(0)->size()-1)%2 == 1) {
                float yDeviance = ((fmod(((float)qrand()),(2000 *deviance)))/1000)-deviance;
                controlPoints.at(n)->append(new ControlPoint(Muta::quantizePoint(point,Muta::BEAT_PIXELS,15)-this->pos()+QPointF(0,7.5+yDeviance),controlPoints.at(n)->size(),-5,-5,10,10,this));
                QObject::connect(controlPoints.at(n)->at(controlPoints.at(n)->size() -1),SIGNAL(mouseMoved(QPointF,int)),this,SLOT(cPointMoved(QPointF,int)));
            } else {
                float yDeviance = 0;
                controlPoints.at(n)->append(new ControlPoint(Muta::quantizePoint(point,Muta::BEAT_PIXELS,15)-this->pos()+QPointF(0,7.5+yDeviance),controlPoints.at(n)->size(),-5,-5,10,10,this));
                QObject::connect(controlPoints.at(n)->at(controlPoints.at(n)->size() -1),SIGNAL(mouseMoved(QPointF,int)),this,SLOT(cPointMoved(QPointF,int)));
            }
        } else {
            float yDeviance = ((fmod(((float)qrand()),(2000 *deviance)))/1000)-deviance;
            controlPoints.at(n)->append(new ControlPoint(Muta::quantizePoint(point,Muta::BEAT_PIXELS,15)-this->pos()+QPointF(0,7.5+yDeviance),controlPoints.at(n)->size(),-5,-5,10,10,this));
            QObject::connect(controlPoints.at(n)->at(controlPoints.at(n)->size() -1),SIGNAL(mouseMoved(QPointF,int)),this,SLOT(cPointMoved(QPointF,int)));
        }
    }

    buildPath();
    setColor();
}

void MutaTendril::cPointMoved(QPointF pos,int num)
{
    for(int n=0;n<numTendrils;n++) {
        controlPoints.at(n)->at(num)->setPos(Muta::quantizePoint(pos,Muta::BEAT_PIXELS,15));
    }
    if(num!=0) {
    //    QPointF curvePoint = (controlPoints.at(num)->pos() - controlPoints.at(controlPoints.size()-2)->pos())*0.5 + controlPoints.at(controlPoints.size()-2)->pos();
    //    curvePoints.at(num-1)->setPos(curvePoint);
    } else {
        //QPointF curvePoint = (controlPoints.at(1)->pos() - controlPoints.at(controlPoints.size()-2)->pos())*0.5 + (controlPoints.at(controlPoints.size()-2)->pos());
        //curvePoints.at(0)->setPos(curvePoint);
        //setPos(pos);
    }
    buildPath();
    setColor();
}

void MutaTendril::setPos(const QPointF &pos)
{
    QGraphicsPathItem::setPos(Muta::quantizePoint(pos,Muta::BEAT_PIXELS,15)+QPointF(0,7.5));
    emit posChanged(objectID,pos);
}


void MutaTendril::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
    QGraphicsPathItem::mouseMoveEvent(event);
    setPos(this->pos());
}

void MutaTendril::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    time++;
    if(time > 6 ) {
        //painter->setBrush(boxBrush);
        //painter->setPen(boxPen);
        //painter->drawRect(path().boundingRect());

        QGraphicsPathItem::paint(painter,option,widget);
    }
}

void MutaTendril::setFinalPoint(QPointF p)
{
    controlPoints.at(0)->last()->setPos(Muta::quantizePoint(p,Muta::BEAT_PIXELS,15) - this->pos()+QPointF(0,7.5));
    QPointF curvePoint = (controlPoints.at(0)->last()->pos() - controlPoints.at(0)->at(controlPoints.at(0)->size()-2)->pos())*0.5 + controlPoints.at(0)->at(controlPoints.at(0)->size()-2)->pos();

    for(int n=1;n<numTendrils;n++) {
        float yDeviance;
        if(mode == MutaTendril::Melding) {
            if(controlPoints.at(0)->size()%2 ==1) {
                yDeviance = 0;
            } else  {
                yDeviance = ((fmod(((float)qrand()),(2000 *deviance)))/1000)-deviance;
            }
        } else {
             yDeviance = ((fmod(((float)qrand()),(2000 *deviance)))/1000)-deviance;
        }
        controlPoints.at(n)->last()->setPos(Muta::quantizePoint(p,Muta::BEAT_PIXELS,15) - this->pos()+QPointF(0,7.5+yDeviance));
        QPointF curvePoint = (controlPoints.at(n)->last()->pos() - controlPoints.at(n)->at(controlPoints.at(n)->size()-2)->pos())*0.5 + controlPoints.at(n)->at(controlPoints.at(n)->size()-2)->pos();
    }
    buildPath();
    setColor();
}

void MutaTendril::setColor()
{
    QColor fillColor;
    QColor firstCPointColor;
    QColor curvePColor;
    switch(layer) {
        case 0:
            fillColor = QColor(227,244,247,255);
            firstCPointColor = QColor(140,204,240,255);
            curvePColor = QColor(64,187,236,255);
            break;
        case 1:
            fillColor = QColor(216,191,215,255);
            firstCPointColor = QColor(194,118,177,255);
            curvePColor = QColor(124,40,125,255);
            break;
        case 2:
            fillColor = QColor(255,153,153);
            firstCPointColor = QColor(242, 99, 75,255);
            curvePColor = QColor(237, 31,36,255);
            break;
        case 3:
            fillColor = QColor(218,242,169,255);
            firstCPointColor = QColor(179,220,53,255);
            curvePColor = QColor(86,107,48,255);
            break;
        case 4:
            fillColor = QColor(	255,204,153,255);
            firstCPointColor = QColor(210,106,40,255);
            curvePColor = QColor(139,70,31,255);
            break;
    }

    QBrush brush;
    brush.setColor(fillColor);
    brush.setStyle(Qt::SolidPattern);

    QPen pen;
    pen.setJoinStyle(Qt::RoundJoin);
    pen.setCapStyle(Qt::RoundCap);
    pen.setBrush(brush);
    pen.setWidth(4);
    pen.setColor(fillColor);
    setPen(pen);
    pen.setWidth(1);

    for(int n=0;n<numTendrils;n++) {
        for(int i=1;i<controlPoints.at(n)->size();i++) {
            controlPoints.at(n)->at(i)->setPen(pen);
            controlPoints.at(n)->at(i)->setBrush(brush);
        }
    }

    brush.setColor(firstCPointColor);
    pen.setBrush(brush);
    pen.setWidth(1);
    pen.setColor(firstCPointColor);
    controlPoints.at(0)->at(0)->setPen(pen);
    controlPoints.at(0)->at(0)->setBrush(brush);

    brush.setColor(curvePColor);
    pen.setBrush(brush);
    pen.setWidth(3);
    pen.setColor(QColor(0,0,0,255));
    pen.setColor(curvePColor);
    /*
    for(int i=0;i<curvePoints.size();i++) {
        curvePoints.at(i)->setPen(pen);
        curvePoints.at(i)->setBrush(brush);
    }
    */
}

QStringList MutaTendril::getProperties()
{
    QStringList properties;
    properties << "ml" << owner << QString::number(x()) << QString::number(y()) << QString::number(layer);
    for(int i=0;i<controlPoints.at(0)->size();i++) {
        properties << QString::number(controlPoints.at(0)->at(i)->x()) << QString::number(controlPoints.at(0)->at(i)->y());
    }

    return properties;
}

int MutaTendril::getLayer()
{
    return layer;
}

QVariant MutaTendril::itemChange(GraphicsItemChange change, const QVariant &value) {
    QVariant variant = QGraphicsPathItem::itemChange(change, value);

    if(change == QGraphicsItem::ItemPositionChange || change == QGraphicsItem::ItemPositionHasChanged)
    {
        variant.setValue(Muta::quantizePoint(variant.toPointF(),Muta::BEAT_PIXELS,15)+QPointF(0,7.5));
    }

    return variant;
}
